{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "CCQY7jpBfMur"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "colab": {},
        "colab_type": "code",
        "id": "z6X9omPnfO_h"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "F1xIRPtY0E1w"
      },
      "source": [
        "# Обзор Keras"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "VyOjQZHhZxaA"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/guide/keras/overview\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />Смотрите на TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ru/guide/keras/overview.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Запустите в Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ru/guide/keras/overview.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />Изучайте код на GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ru/guide/keras/overview.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Скачайте ноутбук</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "fj66ZXAzrJC2"
      },
      "source": [
        "Note: Данный раздел переведён с помощью русскоязычного сообщества Tensorflow на общественных началах. Поскольку перевод не является официальным, мы не гарантируем, что он на 100% точен и соответствует [официальной документации на английском языке](https://www.tensorflow.org/?hl=en). Если у вас есть предложения по исправлению перевода, мы будем очень рады увидеть pull request в репозиторий [tensorflow/docs-l10n](https://github.com/tensorflow/docs-l10n) на GitHub. Если вы хотите помочь сделать документацию по Tensorflow лучше (выполнить перевод или проверить перевод, подготовленный кем-то другим), напишите нам на [docs-ru@tensorflow.org list](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ru)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "VUJTep_x5-R8"
      },
      "source": [
        "Это руководство даст вам основы для начала работы с Keras. Чтение займет 10 минут."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "IsK5aF2xZ-40"
      },
      "source": [
        "## Импортируйте tf.keras\n",
        "\n",
        "`tf.keras` является реализацией TensorFlow\n",
        "[спецификации Keras API](https://keras.io). Это высокоуровневый\n",
        "API для построения и обучения моделей включающий первоклассную поддержку для\n",
        "TensorFlow-специфичной функциональности, такой как [eager execution](../eager.ipynb),\n",
        "конвейеры `tf.data`, и [Estimators](../estimator.ipynb).\n",
        "`tf.keras` делает использование TensorFlow проще не жертвуя при этом гибкостью и\n",
        "производительностью.\n",
        "\n",
        "Для начала, импортируйте `tf.keras` как часть установки вашей TensorFlow:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "TgPcBFru0E1z"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "\n",
        "from tensorflow import keras"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "lj03RamP0E13"
      },
      "source": [
        "`tf.keras` может выполнять любой Keras-совместимый код, но имейте ввиду:\n",
        "\n",
        "* Версия `tf.keras` в последнем релизе TensorFlow может отличаться от\n",
        "  последней версии `keras` в PyPI. Проверьте `tf.keras.__version__`.\n",
        "* При [сохранении весоа моделей](./save_and_serialize.ipynb), `tf.keras` делает это по умолчанию\n",
        "  [в формате checkpoint](../checkpoint.ipynb). Передайте параметр `save_format='h5'` для\n",
        "  использования HDF5 (или добавьте к имени файла расширение `.h5`)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "7e1LPcXx0gR6"
      },
      "source": [
        "## Постройте простую модель\n",
        "\n",
        "### Последовательная модель\n",
        "\n",
        "В Keras, вы собираете *слои (layers)* для построения *моделей (models)*. Модель это (обычно) граф\n",
        "слоев. Наиболее распространенным видом модели является стек слоев:\n",
        "модель `tf.keras.Sequential`.\n",
        "\n",
        "Построение простой полносвязной сети (т.е. многослойного перцептрона):"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "WM-DUVQB0E14"
      },
      "outputs": [],
      "source": [
        "from tensorflow.keras import layers\n",
        "\n",
        "model = tf.keras.Sequential()\n",
        "# Добавим полносвязный слой с 64 узлами к модели:\n",
        "model.add(layers.Dense(64, activation='relu'))\n",
        "# Добавим другой слой:\n",
        "model.add(layers.Dense(64, activation='relu'))\n",
        "# Добавим слой softmax с 10 выходами:\n",
        "model.add(layers.Dense(10, activation='softmax'))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "I2oH0-cxH7YA"
      },
      "source": [
        "Вы можете найти короткий, но полный пример того, как использовать последовательные (Sequential) модели [здесь](https://www.tensorflow.org/tutorials/quickstart/beginner).\n",
        "\n",
        "Чтобы узнать о построении более сложных чем последовательные (Sequential), см:\n",
        "- [Руководство по Keras Functional API](./functional.ipynb)\n",
        "- [Руководство по написанию слоев и моделей с сабклассингом с нуля](./custom_layers_and_models.ipynb)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "-ztyTipu0E18"
      },
      "source": [
        "### Настройте слои\n",
        "\n",
        "Доступно много разновидностей слоев `tf.keras.layers`. Большинство из них используют общий конструктор\n",
        "аргументов:\n",
        "\n",
        "* `activation`: Установка функции активации для слоя. В этом параметре\n",
        "  указывается имя встроенной функции или вызываемый объект. У параметра\n",
        "  нет значения по умолчанию.\n",
        "* `kernel_initializer` И `bias_initializer`: Схемы инициализации\n",
        "  создающие веса слоя (ядро и сдвиг). В этом параметре может быть имя\n",
        "  или вызываемый объект. По умолчанию используется инициализатор `\"Glorot uniform\"`.\n",
        "* `kernel_regularizer` и `bias_regularizer`: Схемы регуляризации\n",
        "  добавляемые к весам слоя (ядро и сдвиг), такие как L1 или L2\n",
        "  регуляризации. По умолчанию регуляризация не устанавливается.\n",
        "\n",
        "Следующие примеры слоев `tf.keras.layers.Dense` используют \n",
        "аргументы конструктора:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "MlL7PBtp0E19"
      },
      "outputs": [],
      "source": [
        "# Создать слой с сигмоидой:\n",
        "layers.Dense(64, activation='sigmoid')\n",
        "# Или:\n",
        "layers.Dense(64, activation=tf.keras.activations.sigmoid)\n",
        "\n",
        "# Линейный слой с регуляризацией L1 с коэфициентом 0.01 примененной к матрице ядра:\n",
        "layers.Dense(64, kernel_regularizer=tf.keras.regularizers.l1(0.01))\n",
        "\n",
        "# Линейный слой с регуляризацией L2 с коэффициентом 0.01 примененной к вектору сдвига:\n",
        "layers.Dense(64, bias_regularizer=tf.keras.regularizers.l2(0.01))\n",
        "\n",
        "# Линейный слой с ядром инициализированным случайной ортогональной матрицей:\n",
        "layers.Dense(64, kernel_initializer='orthogonal')\n",
        "\n",
        "# Линейный слой с вектором сдвига инициализированным значениями 2.0:\n",
        "layers.Dense(64, bias_initializer=tf.keras.initializers.Constant(2.0))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "9NR6reyk0E2A"
      },
      "source": [
        "## Обучение и оценка\n",
        "\n",
        "### Настройка обучения\n",
        "\n",
        "После того как модель сконструирована, настройте процесс ее обучения вызовом\n",
        "метода `compile`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "sJ4AOn090E2A"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential([\n",
        "# Добавляем полносвязный слой с 64 узлами к модели:\n",
        "layers.Dense(64, activation='relu', input_shape=(32,)),\n",
        "# Добавляем другой слой:\n",
        "layers.Dense(64, activation='relu'),\n",
        "# Добавляем слой softmax с 10 выходами:\n",
        "layers.Dense(10, activation='softmax')])\n",
        "\n",
        "model.compile(optimizer=tf.keras.optimizers.Adam(0.01),\n",
        "              loss='categorical_crossentropy',\n",
        "              metrics=['accuracy'])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "HG-RAa9F0E2D"
      },
      "source": [
        "`tf.keras.Model.compile` принимает три важных аргумента:\n",
        "\n",
        "* `optimizer`: Этот объект определяет процедуру обучения. Передайте в него экземпляры\n",
        "  оптимизатора из модуля `tf.keras.optimizers`, такие как\n",
        "  `tf.keras.optimizers.Adam` или\n",
        "  `tf.keras.optimizers.SGD`. Если вы просто хотите использовать значения по умолчанию, вы также можете указать оптимизаторы ключевыми словами, такими как `'adam'` или `'sgd'`.\n",
        "* `loss`: Это функция которая минимизируется в процессе обучения. Среди распространенных вариантов\n",
        "  mean square error (`mse`), `categorical_crossentropy`, и\n",
        "  `binary_crossentropy`. Функции потерь указываются по имени или по\n",
        "  передаче вызываемого объекта из модуля `tf.keras.losses`.\n",
        "* `metrics`: Используются для мониторинга обучения. Это строковые имена или вызываемые объекты из\n",
        "  модуля `tf.keras.metrics`.\n",
        "* Кроме того, чтобы быть уверенным, что модель обучается и оценивается eagerly, проверьте что вы передали компилятору параметр `run_eagerly=True`\n",
        "\n",
        "\n",
        "Далее посмотрим несколько примеров конфигурации модели для обучения:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "St4Mgdar0E2E"
      },
      "outputs": [],
      "source": [
        "# Сконфигурируем модель для регрессии со среднеквадратичной ошибкой.\n",
        "model.compile(optimizer=tf.keras.optimizers.Adam(0.01),\n",
        "              loss='mse',       # срееднеквадратичная ошибка\n",
        "              metrics=['mae'])  # средняя абсолютная ошибка\n",
        "\n",
        "# Сконфигурируем модель для категориальной классификации.\n",
        "model.compile(optimizer=tf.keras.optimizers.RMSprop(0.01),\n",
        "              loss=tf.keras.losses.CategoricalCrossentropy(),\n",
        "              metrics=[tf.keras.metrics.CategoricalAccuracy()])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "yjI5rbi80E2G"
      },
      "source": [
        "### Обучение на данных NumPy\n",
        "\n",
        "Для небольших датасетов используйте помещающиеся в память массивы [NumPy](https://www.numpy.org/)\n",
        "для обучения и оценки модели. Модель  \"обучается\" на тренировочных даннных\n",
        "используя метод `fit`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "3CvP6L-m0E2I"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "\n",
        "data = np.random.random((1000, 32))\n",
        "labels = np.random.random((1000, 10))\n",
        "\n",
        "model.fit(data, labels, epochs=10, batch_size=32)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "N-pnVaFe0E2N"
      },
      "source": [
        "`tf.keras.Model.fit` принимает три важных аргумента:\n",
        "\n",
        "* `epochs`: Обучение разбито на *эпохи*. Эпоха это одна итерация\n",
        "  по всем входным данным (это делается небольшими партиями).\n",
        "* `batch_size`: При передаче данных NumPy, модель разбивает данные на меньшие\n",
        "  блоки (batches) и итерирует по этим блокам во время обучения. Это число\n",
        "  указывает размер каждого блока данных. Помните, что последний блок может быть меньшего\n",
        "  размера если общее число записей не делится на размер партии.\n",
        "* `validation_data`: При прототипировании модели вы хотите легко отслеживать её\n",
        "  производительность на валидационных данных. Передача с этим аргументом кортежа входных данных\n",
        "  и меток позволяет модели отопражать значения функции потерь и метрики в режиме вывода\n",
        "  для передаваемых данных в конце каждой эпохи.\n",
        "\n",
        "Вот пример использования `validation_data`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "gFcXzVQa0E2N"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "\n",
        "data = np.random.random((1000, 32))\n",
        "labels = np.random.random((1000, 10))\n",
        "\n",
        "val_data = np.random.random((100, 32))\n",
        "val_labels = np.random.random((100, 10))\n",
        "\n",
        "model.fit(data, labels, epochs=10, batch_size=32,\n",
        "          validation_data=(val_data, val_labels))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "-6ImyXzz0E2Q"
      },
      "source": [
        "### Обучение с использованием наборов данных tf.data\n",
        "\n",
        "Используйте [Datasets API](../data.ipynb) для масштабирования больших баз данных\n",
        "или обучения на нескольких устройствах. Передайте экземпляр `tf.data.Dataset` в метод\n",
        "`fit`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "OziqhpIj0E2R"
      },
      "outputs": [],
      "source": [
        "# Создает экземпляр учебного датасета:\n",
        "dataset = tf.data.Dataset.from_tensor_slices((data, labels))\n",
        "dataset = dataset.batch(32)\n",
        "\n",
        "model.fit(dataset, epochs=10)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "I7BcMHkB0E2U"
      },
      "source": [
        "Поскольку `Dataset` выдает данные пакетами, этот кусок кода не требует аргумента `batch_size`.\n",
        "\n",
        "Датасеты могут быть также использованы для валидации:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "YPMb3A0N0E2V"
      },
      "outputs": [],
      "source": [
        "dataset = tf.data.Dataset.from_tensor_slices((data, labels))\n",
        "dataset = dataset.batch(32)\n",
        "\n",
        "val_dataset = tf.data.Dataset.from_tensor_slices((val_data, val_labels))\n",
        "val_dataset = val_dataset.batch(32)\n",
        "\n",
        "model.fit(dataset, epochs=10,\n",
        "          validation_data=val_dataset)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "IgGdlXso0E2X"
      },
      "source": [
        "### Оценка и предсказание\n",
        "\n",
        "Методы `tf.keras.Model.evaluate` и `tf.keras.Model.predict` могут использовать данные\n",
        "NumPy и `tf.data.Dataset`.\n",
        "\n",
        "Вот так можно *оценить* потери в режиме вывода и метрики для предоставленных данных:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "mhDbOHEK0E2Y"
      },
      "outputs": [],
      "source": [
        "# С массивом Numpy\n",
        "data = np.random.random((1000, 32))\n",
        "labels = np.random.random((1000, 10))\n",
        "\n",
        "model.evaluate(data, labels, batch_size=32)\n",
        "\n",
        "# С датасетом\n",
        "dataset = tf.data.Dataset.from_tensor_slices((data, labels))\n",
        "dataset = dataset.batch(32)\n",
        "\n",
        "model.evaluate(dataset)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "UXUTmDfb0E2b"
      },
      "source": [
        "А вот как *предсказать* вывод последнего уровня в режиме вывода для предоставленных данных,\n",
        "в виде массива NumPy:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "9e3JsSoQ0E2c"
      },
      "outputs": [],
      "source": [
        "result = model.predict(data, batch_size=32)\n",
        "print(result.shape)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "GuTb71gYILLG"
      },
      "source": [
        "Полное руководство по обучению и оценке модели, включая описание написания пользовательских циклов обучения с нуля, см. в [руководстве по обучению и оценке] (./ train_and_evaluate.ipynb)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "fzEOW4Cn0E2h"
      },
      "source": [
        "## Построение сложных моделей\n",
        "\n",
        "### The Functional API\n",
        "\n",
        " Модель `tf.keras.Sequential` это простой стек слоев с помощью которого\n",
        "нельзя представить произвольную модель. Используйте\n",
        "[Keras functional API](./functional.ipynb)\n",
        "для построения сложных топологий моделей, таких как:\n",
        "\n",
        "* Модели с несколькими входами,\n",
        "* Модели с несколькими выходами,\n",
        "* Модели с общими слоями (один и тот же слой вызывается несколько раз),\n",
        "* Модели с непоследовательными потоками данных (напр. остаточные связи).\n",
        "\n",
        "Построение модели с functional API работает следующим образом:\n",
        "\n",
        "1. Экземпляр слоя является вызываемым и возвращает тензор.\n",
        "2. Входные и выходные тензоры используются для определения экземпляра\n",
        "    `tf.keras.Model`\n",
        "3. Эта модель обучается точно так же как и `Sequential` модель.\n",
        "\n",
        "Следующий пример использует functional API для построения простой, полносвязной\n",
        "сети:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "mROj832r0E2i"
      },
      "outputs": [],
      "source": [
        "inputs = tf.keras.Input(shape=(32,))  # Возвращает входной плейсхолдер\n",
        "\n",
        "# Экземпляр слоя вызывается на тензор и возвращает тензор.\n",
        "x = layers.Dense(64, activation='relu')(inputs)\n",
        "x = layers.Dense(64, activation='relu')(x)\n",
        "predictions = layers.Dense(10, activation='softmax')(x)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "AFmspHeG1_W7"
      },
      "source": [
        "Создайте экземпляр модели с данными входами и выходами."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "5k5uzlyu16HM"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Model(inputs=inputs, outputs=predictions)\n",
        "\n",
        "# Шаг компиляции определяет конфигурацию обучения.\n",
        "model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001),\n",
        "              loss='categorical_crossentropy',\n",
        "              metrics=['accuracy'])\n",
        "\n",
        "# Обучение  за 5 эпох\n",
        "model.fit(data, labels, batch_size=32, epochs=5)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "EcKSLH3i0E2k"
      },
      "source": [
        "### Сабклассинг моделей\n",
        "\n",
        "Создайте полностью настраиваемую модель с помощью сабклассинга `tf.keras.Model` и определения\n",
        "вашего собственного прямого распространения. Создайте слои в методе `__init__` и установите их как\n",
        "атрибуты экземпляра класса. Определите прямое распространение в методе `call`.\n",
        "\n",
        "Сабклассинг модели особенно полезен когда включен\n",
        "[eager execution](../eager.ipynb), поскольку он позволяет написать \n",
        "прямое распространение императивно.\n",
        "\n",
        "Примечание: если вам нужно чтобы ваша модель *всегда* выполнялась императивно, вы можете установить `dynamic=True` когда вызываете конструктор `super`.\n",
        "\n",
        "> Ключевой момент: Используйте правильный API для работы. Хоть сабклассинг модели обеспечивает\n",
        "гибкость, за нее приходится платить большей сложностью и большими возможностями для\n",
        "пользовательских ошибок. Если это возможно выбирайте functional API.\n",
        "\n",
        "Следующий пример показывает сабклассированную `tf.keras.Model` использующую пользовательское прямое\n",
        "распространение, которое не обязательно выполнять императивно:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "KLiHWzcn2Fzk"
      },
      "outputs": [],
      "source": [
        "class MyModel(tf.keras.Model):\n",
        "\n",
        "  def __init__(self, num_classes=10):\n",
        "    super(MyModel, self).__init__(name='my_model')\n",
        "    self.num_classes = num_classes\n",
        "    # Определим свои слои тут.\n",
        "    self.dense_1 = layers.Dense(32, activation='relu')\n",
        "    self.dense_2 = layers.Dense(num_classes, activation='sigmoid')\n",
        "\n",
        "  def call(self, inputs):\n",
        "    # Определим тут свое прямое распространение,\n",
        "    # с использованием ранее определенных слоев (в `__init__`).\n",
        "    x = self.dense_1(inputs)\n",
        "    return self.dense_2(x)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ShDD4fv72KGc"
      },
      "source": [
        "Создайте экземпляр класса новой модели:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "42C-qQHm0E2l"
      },
      "outputs": [],
      "source": [
        "model = MyModel(num_classes=10)\n",
        "\n",
        "# Шаг компиляции определяет конфигурацию обучения.\n",
        "model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001),\n",
        "              loss='categorical_crossentropy',\n",
        "              metrics=['accuracy'])\n",
        "\n",
        "# Обучение за 5 эпох.\n",
        "model.fit(data, labels, batch_size=32, epochs=5)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "yqRQiKj20E2o"
      },
      "source": [
        "### Пользовательские слои\n",
        "\n",
        "Создайте пользовательский слой сабклассингом `tf.keras.layers.Layer` и реализацией\n",
        "следующих методов:\n",
        "\n",
        "* `__init__`: Опционально определите подслои которые будут использоваться в этом слое.\n",
        "* `build`: Создайте веса слоя. Добавьте веса при помощи метода\n",
        "  `add_weight`.\n",
        "* `call`: Определите прямое распространение.\n",
        "* Опционально, слой может быть сериализован реализацией метода `get_config`\n",
        "  и метода класса `from_config`.\n",
        "\n",
        "Ниже пример пользовательского слоя который осуществляет умножение матрицы (`matmul`) поданной на вход\n",
        "с матрицей ядра:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "l7BFnIHr2WNc"
      },
      "outputs": [],
      "source": [
        "class MyLayer(layers.Layer):\n",
        "\n",
        "  def __init__(self, output_dim, **kwargs):\n",
        "    self.output_dim = output_dim\n",
        "    super(MyLayer, self).__init__(**kwargs)\n",
        "\n",
        "  def build(self, input_shape):\n",
        "    # Создадим обучаемую весовую переменную для этого слоя.\n",
        "    self.kernel = self.add_weight(name='kernel',\n",
        "                                  shape=(input_shape[1], self.output_dim),\n",
        "                                  initializer='uniform',\n",
        "                                  trainable=True)\n",
        "\n",
        "  def call(self, inputs):\n",
        "    return tf.matmul(inputs, self.kernel)\n",
        "\n",
        "  def get_config(self):\n",
        "    base_config = super(MyLayer, self).get_config()\n",
        "    base_config['output_dim'] = self.output_dim\n",
        "    return base_config\n",
        "\n",
        "  @classmethod\n",
        "  def from_config(cls, config):\n",
        "    return cls(**config)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "8wXDRgXV2ZrF"
      },
      "source": [
        "Создайте модель с использованием вашего пользовательского слоя:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "uqH-cY0h0E2p"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential([\n",
        "    MyLayer(10),\n",
        "    layers.Activation('softmax')])\n",
        "\n",
        "# Шаг компиляции определяет конфигурацию обучения\n",
        "model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001),\n",
        "              loss='categorical_crossentropy',\n",
        "              metrics=['accuracy'])\n",
        "\n",
        "# Обучение за 5 эпох.\n",
        "model.fit(data, labels, batch_size=32, epochs=5)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "llipvR5wIl_t"
      },
      "source": [
        "Узнайте больше о создании новых слоев и моделей с нуля с помощью сабклассинга в [Руководстве написания слоев и моделей с нуля](./custom_layers_and_models.ipynb)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Lu8cc3AJ0E2v"
      },
      "source": [
        "## Колбеки\n",
        "\n",
        "Колбек это объект переданный модели чтобы кастомизировать и расширить ее поведение\n",
        "во время обучения. Вы можете написать свой пользовательский колбек или использовать встроенный\n",
        "`tf.keras.callbacks` который включает:\n",
        "\n",
        "* `tf.keras.callbacks.ModelCheckpoint`: Сохранение контрольных точек модели за\n",
        "  регулярные интервалы.\n",
        "* `tf.keras.callbacks.LearningRateScheduler`: Динамичное изменение шага\n",
        "  обучения.\n",
        "* `tf.keras.callbacks.EarlyStopping`: Остановка обучения в том случае когда\n",
        "  результат на валидации перестает улучшаться.\n",
        "* `tf.keras.callbacks.TensorBoard`: Мониторинг поведения модели с помощью\n",
        "  [TensorBoard](https://tensorflow.org/tensorboard).\n",
        "\n",
        "Для использования `tf.keras.callbacks.Callback`, передайте ее методу модели `fit`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "rdYwzSYV0E2v"
      },
      "outputs": [],
      "source": [
        "callbacks = [\n",
        "  # Остановить обучение если `val_loss` перестанет улучшаться в течение 2 эпох\n",
        "  tf.keras.callbacks.EarlyStopping(patience=2, monitor='val_loss'),\n",
        "  # Записать логи TensorBoard в каталог `./logs`\n",
        "  tf.keras.callbacks.TensorBoard(log_dir='./logs')\n",
        "]\n",
        "model.fit(data, labels, batch_size=32, epochs=5, callbacks=callbacks,\n",
        "          validation_data=(val_data, val_labels))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ghhaGfX62abv"
      },
      "source": [
        "<a name='save_and_restore'></a>\n",
        "## Сохранение и восстановление"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "qnl7K-aI0E2z"
      },
      "source": [
        "<a name=\"weights_only\"></a>\n",
        "### Сохранение только значений весов\n",
        "\n",
        "Сохраните и загрузите веса модели с помощью `tf.keras.Model.save_weights`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "uQIANjB94fLB"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential([\n",
        "layers.Dense(64, activation='relu', input_shape=(32,)),\n",
        "layers.Dense(10, activation='softmax')])\n",
        "\n",
        "model.compile(optimizer=tf.keras.optimizers.Adam(0.001),\n",
        "              loss='categorical_crossentropy',\n",
        "              metrics=['accuracy'])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "4eoHJ-ny0E21"
      },
      "outputs": [],
      "source": [
        "# Сохраним веса в файл TensorFlow Checkpoint\n",
        "model.save_weights('./weights/my_model')\n",
        "\n",
        "# Восстановим состояние модели,\n",
        "# для этого необходима модель с такой же архитектурой.\n",
        "model.load_weights('./weights/my_model')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "u25Id3xe0E25"
      },
      "source": [
        "По умолчанию веса модели сохраняются в формате\n",
        "[TensorFlow checkpoint](../checkpoint.ipynb). Веса могут быть также\n",
        "сохранены в формате Keras HDF5 (значение по умолчанию для универсальной\n",
        "реализации Keras):"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "JSAYoFEd0E26"
      },
      "outputs": [],
      "source": [
        "# Сохранение весов в файл HDF5\n",
        "model.save_weights('my_model.h5', save_format='h5')\n",
        "\n",
        "# Восстановление состояния модели\n",
        "model.load_weights('my_model.h5')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "mje_yKL10E29"
      },
      "source": [
        "### Сохранение только конфигурации модели\n",
        "\n",
        "Конфигурация модели может быть сохранена - это сериализует архитектуру модели\n",
        "без всяких весов. Сохраненная конфигурация может восстановить и инициализировать ту же\n",
        "модель, даже без кода определяющего исходную модель. Keras поддерживает\n",
        "форматы сериализации JSON и YAML:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "EbET0oJTzGkq"
      },
      "outputs": [],
      "source": [
        "# Сериализация модели в формат JSON\n",
        "json_string = model.to_json()\n",
        "json_string"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "pX_badhH3yWV"
      },
      "outputs": [],
      "source": [
        "import json\n",
        "import pprint\n",
        "pprint.pprint(json.loads(json_string))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Q7CIa05r4yTb"
      },
      "source": [
        "Восстановление модели (заново инициализированной) из JSON:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "J9UFv9k00E2_"
      },
      "outputs": [],
      "source": [
        "fresh_model = tf.keras.models.model_from_json(json_string)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "t5NHtICh4uHK"
      },
      "source": [
        "Сериализация модели в формат YAML требует установки `pyyaml` *перед тем как импортировать TensorFlow*:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "aj24KB3Z36S4"
      },
      "outputs": [],
      "source": [
        "yaml_string = model.to_yaml()\n",
        "print(yaml_string)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "O53Kerfl43v7"
      },
      "source": [
        "Восстановление модели из YAML:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "77yRuwg03_MG"
      },
      "outputs": [],
      "source": [
        "fresh_model = tf.keras.models.model_from_yaml(yaml_string)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "xPvOSSzM0E3B"
      },
      "source": [
        "Внимание: сабклассированные модели не сериализуемы, потому что их архитектура\n",
        "определяется кодом Python в теле метода `call`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "iu8qMwld4-71"
      },
      "source": [
        "### Сохранение всей модели в один файл\n",
        "\n",
        "Вся модель может быть сохранена в файл содержащий значения весов, конфигурацию\n",
        "модели, и даже конфигурацию оптимизатора. Это позволит вам\n",
        "установить контрольную точку модели и продолжить обучение позже с точно того же положения\n",
        "даже без доступа к исходному коду."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "45oNY34Z0E3C"
      },
      "outputs": [],
      "source": [
        "# Создадим простую модель\n",
        "model = tf.keras.Sequential([\n",
        "  layers.Dense(10, activation='softmax', input_shape=(32,)),\n",
        "  layers.Dense(10, activation='softmax')\n",
        "])\n",
        "model.compile(optimizer='rmsprop',\n",
        "              loss='categorical_crossentropy',\n",
        "              metrics=['accuracy'])\n",
        "model.fit(data, labels, batch_size=32, epochs=5)\n",
        "\n",
        "\n",
        "# Сохраним всю модель в файл HDF5\n",
        "model.save('my_model.h5')\n",
        "\n",
        "# Пересоздадим в точности эту модель включая веса и оптимизатор.\n",
        "model = tf.keras.models.load_model('my_model.h5')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "wGVBURDtI_I6"
      },
      "source": [
        "Узнайте больше о сохранении и сериализации моделей Keras в руководстве по [сохранению и сериализации моделей](./save_and_serialize.ipynb)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "PMOWhDOB0E3E"
      },
      "source": [
        "<a name=\"eager_execution\"></a>\n",
        "## Eager execution\n",
        "\n",
        "[Eager execution](../eager.ipynb) это императивное программирование\n",
        "среда которая выполняет операции немедленно. Это не требуется для \n",
        "Keras, но поддерживается `tf.keras` и полезно для проверки вашей программы и\n",
        "отладки.\n",
        "\n",
        "Все строящие модели API `tf.keras` совместимы eager execution.\n",
        "И хотя могут быть использованы `Sequential` и functional API, eager execution\n",
        "особенно полезно при *сабклассировании модели* и построении *пользовательских слоев* — эти API\n",
        "требуют от вас написание прямого распространения в виде кода (вместо API которые\n",
        "создают модели путем сборки существующих слоев).\n",
        "\n",
        "См [руководство eager execution](../eager.ipynb) для\n",
        "примеров использования моделей Keras с пользовательскими циклами обучения и `tf.GradientTape`.\n",
        "Вы можете также найти полный коротки пример [тут](https://www.tensorflow.org/tutorials/quickstart/advanced)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "2wG3NVco5B5V"
      },
      "source": [
        "## Распределение\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "6PJZ6e9J5JHF"
      },
      "source": [
        "### Множественные GPU\n",
        "\n",
        "`tf.keras` модели можно запускать на множестве GPU с использованием\n",
        "`tf.distribute.Strategy`. Этот API обеспечивает распределенное\n",
        "обучение на нескольких GPU практически без изменений в существующем коде.\n",
        "\n",
        "На данный момент, `tf.distribute.MirroredStrategy` единственная поддерживаемая\n",
        "стратегия распределения. `MirroredStrategy` выполняет репликацию в графах с\n",
        "синхронным обучением используя all-reduce на одной машине. Для использования\n",
        "`distribute.Strategy` , вложите инсталляцию оптимизатора, конструкцию и компиляцию модели в `Strategy`'s `.scope()`, затем\n",
        "обучите модель.\n",
        "\n",
        "Следующий пример распределяет `tf.keras.Model` между множеством GPU на\n",
        "одной машине.\n",
        "\n",
        "Сперва определим модель внутри области распределенной стратегии:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "sbaRr7g-0E3I"
      },
      "outputs": [],
      "source": [
        "strategy = tf.distribute.MirroredStrategy()\n",
        "\n",
        "with strategy.scope():\n",
        "  model = tf.keras.Sequential()\n",
        "  model.add(layers.Dense(16, activation='relu', input_shape=(10,)))\n",
        "  model.add(layers.Dense(1, activation='sigmoid'))\n",
        "\n",
        "  optimizer = tf.keras.optimizers.SGD(0.2)\n",
        "\n",
        "  model.compile(loss='binary_crossentropy', optimizer=optimizer)\n",
        "\n",
        "model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "rO9MiL6X0E3O"
      },
      "source": [
        "Затем обучим модель на данных как обычно:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "BEwFq4PM0E3P"
      },
      "outputs": [],
      "source": [
        "x = np.random.random((1024, 10))\n",
        "y = np.random.randint(2, size=(1024, 1))\n",
        "x = tf.cast(x, tf.float32)\n",
        "dataset = tf.data.Dataset.from_tensor_slices((x, y))\n",
        "dataset = dataset.shuffle(buffer_size=1024).batch(32)\n",
        "\n",
        "model.fit(dataset, epochs=1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "N6BXU5F90E3U"
      },
      "source": [
        "Для дополнительной информации см. [полное руководство по распределенному обучению наа TensorFlow](../distributed_training.ipynb)."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "overview.ipynb",
      "private_outputs": true,
      "provenance": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
